{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Lesson 6\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Sharpe Ratio based Portfolio Optimization "
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![](Lesson6GoalHeaderImage.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 6.1  Introduction"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Sharpe Ratio**, developed by Nobel Laureate William F Sharpe [SHA 66], is a measure of calculating risk adjusted return. It serves to help investors know about the returns on their investments relative to the risks they hold. The Sharpe Ratio is defined as"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![](Lesson6Eqn6_1.png)\n",
    "<h5 align=\"right\">..........(6.1)</h5>\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "where $r_x$ is the average rate of return on the investment $x$, $R_f$,  the best available **risk free rate of return** and $\\sigma$ the standard deviation of $r_x$, which denotes the risk on the investment. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Higher the Sharpe Ratio, more is the excess returns over that of holding a risk free investment, relative to the increased volatility that the investment is exposed to. A Sharpe Ratio of 0, needless to say,  only denotes the investment to be risk-free or one that does not yield any excess return. In practice, while a Sharpe ratio of 1 marks the investment to be acceptable or good for investors, a value less than 1 grades the investment as  sub-optimal,  and values greater than 1 and moving towards 2 or 3, grades the investment as  highly superior. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 6.2 Maximizing Sharpe Ratio"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Having understood the significance of the Sharpe Ratio, let us suppose an investor wishes to make an investment in  assets in such a way that the Sharpe Ratio of the portfolio would be the best possible or the maximum, that can be ensured for the investment.  \n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let P be a portfolio comprising assets $A_1, A_2, ...A_N$, with $\\mu_1, \\mu_2, ...\\mu_N$ as the asset returns and $W_1, W_2, ...W_N$ as the weights. \n",
    " "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The portfolio return $r$ determined by a weighted summation of its individual asset returns is given by, $\\sum\\left({W_i.\\mu_i}\\right)$ and the risk is given by $\\sqrt{\\sum\\sum {W_i.W_j.\\sigma_{ij}} } $. (See **Lesson 1 Fundamentals of Risk and Return of a Portfolio** to know about risk and return of a portfolio).  "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To keep the discussion simple for now, let us suppose that  the investor decides to enforce only **basic constraints** on the portfolio. (See Sec. 5.2 of **Lesson 5 Mean Variance Optimization of Portfolios** to know about basic constraints).  \n",
    "  \n",
    "The mathematical model for the Sharpe Ratio based Portfolio Optimization is given by, "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![](Lesson6Eqn6_2.png)\n",
    "<h5 align=\"right\">..........(6.2)</h5>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The numerator of the objective function denotes the excess returns of the investment over that of a risk free asset $R_f$ and the denominator the risk of the investment. The objective is to maximize the Sharpe Ratio. The basic constraints indicate that the investor wishes to have a fully invested portfolio. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 6.3 Solving the Sharpe Ratio Optimization Model"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To solve the Sharpe Ratio maximization model represented by (6.2), we make use of the **minimize** library function from **scipy.optimize** package of Python. However, since the original objective function insists on maximization as opposed to minimization demanded by the **minimize** solver, the **principal of  duality** borrowed from Optimization Theory is employed to undertake the transformation. According to the principle,  \n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![](Lesson6Eqn6_3.png)\n",
    "<h5 align=\"right\">..........(6.3)</h5>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The Python code for the function **MaximizeSharpeRatioOptimization** which defines the objective function  and the basic constraints represented by (6.2),  is shown below: "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [],
   "source": [
    "#function to undertake Sharpe Ratio maximization subject to \n",
    "#basic constraints of the portfolio\n",
    "\n",
    "#dependencies\n",
    "import numpy as np\n",
    "from scipy import optimize \n",
    "\n",
    "def MaximizeSharpeRatioOptmzn(MeanReturns, CovarReturns, RiskFreeRate, PortfolioSize):\n",
    "    \n",
    "    # define maximization of Sharpe Ratio using principle of duality\n",
    "    def  f(x, MeanReturns, CovarReturns, RiskFreeRate, PortfolioSize):\n",
    "        funcDenomr = np.sqrt(np.matmul(np.matmul(x, CovarReturns), x.T) )\n",
    "        funcNumer = np.matmul(np.array(MeanReturns),x.T)-RiskFreeRate\n",
    "        func = -(funcNumer / funcDenomr)\n",
    "        return func\n",
    "\n",
    "    #define equality constraint representing fully invested portfolio\n",
    "    def constraintEq(x):\n",
    "        A=np.ones(x.shape)\n",
    "        b=1\n",
    "        constraintVal = np.matmul(A,x.T)-b \n",
    "        return constraintVal\n",
    "    \n",
    "    \n",
    "    #define bounds and other parameters\n",
    "    xinit=np.repeat(0.33, PortfolioSize)\n",
    "    cons = ({'type': 'eq', 'fun':constraintEq})\n",
    "    lb = 0\n",
    "    ub = 1\n",
    "    bnds = tuple([(lb,ub) for x in xinit])\n",
    "    \n",
    "    #invoke minimize solver\n",
    "    opt = optimize.minimize (f, x0 = xinit, args = (MeanReturns, CovarReturns,\\\n",
    "                             RiskFreeRate, PortfolioSize), method = 'SLSQP',  \\\n",
    "                             bounds = bnds, constraints = cons, tol = 10**-3)\n",
    "    \n",
    "    return opt\n",
    "    "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The Sharpe Ratio optimization requires the computation of risk and return of the portfolio. The asset returns computing function **StockReturnsComputing**, is reproduced here for the reader's convenience. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [],
   "source": [
    "# function computes asset returns \n",
    "def StockReturnsComputing(StockPrice, Rows, Columns):\n",
    "    \n",
    "    import numpy as np\n",
    "    \n",
    "    StockReturn = np.zeros([Rows-1, Columns])\n",
    "    for j in range(Columns):        # j: Assets\n",
    "        for i in range(Rows-1):     # i: Daily Prices\n",
    "            StockReturn[i,j]=((StockPrice[i+1, j]-StockPrice[i,j])/StockPrice[i,j])* 100\n",
    "\n",
    "    return StockReturn"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 6.4  Case Study"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    " Let us suppose that an investor decides to invest in a $k$-portfolio ($k$-portfolio 1) comprising the  following  Dow stocks. ($k$ portfolio 1, is  detailed and listed in **Lesson 3 Heuristic Portfolio Selection**)  \n",
    "\n",
    "**𝑘-portfolio 1**:  \n",
    "\n",
    "{Coca-Cola (KO), United Health (UNH), Walt Disney (DIS), IBM (IBM), Cisco (CSCO), JPMorgan Chase (JPM), Goldman Sachs (GS), Walgreens Boots Alliance (WBA), Apple (AAPL), Home Depot (HD), American Express (AXP), McDonald's (MCD), Merck (MRK), Boeing (BA), Caterpillar (CAT)}       \n",
    "\n",
    "The investor desires to explore the optimal portfolio set that would yield the maximal Sharpe Ratio.  The objective is to find out  the optimal weights that will ensure maximal Sharpe Ratio for the portfolio.\n",
    "\n",
    "The following Python code reads the dataset concerned, computes the stock returns using the Python function **StockReturnsComputing** and obtains the mean returns and the variance-covariance matrix of returns. \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Asset labels of k-portfolio 1: \n",
      " ['AAPL', 'AXP', 'BA', 'CAT', 'CSCO', 'DIS', 'GS', 'HD', 'IBM', 'JPM', 'KO', 'MCD', 'MRK', 'UNH', 'WBA']\n",
      "\n",
      "Mean Returns:\n",
      " [ 0.09   0.029  0.1    0.039  0.081  0.04   0.033  0.085 -0.016  0.06\n",
      "  0.019  0.057  0.036  0.095 -0.002]\n",
      "\n",
      "Variance-Covariance Matrix of Returns:\n",
      " [[2.375 0.672 0.962 1.042 0.999 0.68  0.954 0.726 0.709 0.825 0.306 0.458\n",
      "  0.534 0.774 0.697]\n",
      " [0.672 1.648 0.8   0.95  0.7   0.569 1.065 0.658 0.663 1.001 0.307 0.35\n",
      "  0.556 0.718 0.667]\n",
      " [0.962 0.8   2.288 1.31  0.89  0.716 1.066 0.747 0.777 0.977 0.381 0.472\n",
      "  0.578 0.745 0.679]\n",
      " [1.042 0.95  1.31  2.733 1.041 0.688 1.321 0.796 0.885 1.169 0.358 0.455\n",
      "  0.616 0.72  0.681]\n",
      " [0.999 0.7   0.89  1.041 1.789 0.713 0.927 0.724 0.817 0.909 0.362 0.477\n",
      "  0.647 0.656 0.707]\n",
      " [0.68  0.569 0.716 0.688 0.713 1.35  0.773 0.586 0.574 0.717 0.302 0.368\n",
      "  0.466 0.557 0.631]\n",
      " [0.954 1.065 1.066 1.321 0.927 0.773 2.114 0.795 0.803 1.554 0.303 0.467\n",
      "  0.705 0.82  0.819]\n",
      " [0.726 0.658 0.747 0.796 0.724 0.586 0.795 1.39  0.619 0.753 0.343 0.472\n",
      "  0.487 0.659 0.689]\n",
      " [0.709 0.663 0.777 0.885 0.817 0.574 0.803 0.619 1.632 0.767 0.372 0.391\n",
      "  0.576 0.564 0.534]\n",
      " [0.825 1.001 0.977 1.169 0.909 0.717 1.554 0.753 0.767 1.702 0.324 0.483\n",
      "  0.675 0.761 0.717]\n",
      " [0.306 0.307 0.381 0.358 0.362 0.302 0.303 0.343 0.372 0.324 0.806 0.36\n",
      "  0.384 0.31  0.355]\n",
      " [0.458 0.35  0.472 0.455 0.477 0.368 0.467 0.472 0.391 0.483 0.36  1.086\n",
      "  0.402 0.43  0.433]\n",
      " [0.534 0.556 0.578 0.616 0.647 0.466 0.705 0.487 0.576 0.675 0.384 0.402\n",
      "  1.504 0.615 0.64 ]\n",
      " [0.774 0.718 0.745 0.72  0.656 0.557 0.82  0.659 0.564 0.761 0.31  0.43\n",
      "  0.615 1.722 0.78 ]\n",
      " [0.697 0.667 0.679 0.681 0.707 0.631 0.819 0.689 0.534 0.717 0.355 0.433\n",
      "  0.64  0.78  2.554]]\n"
     ]
    }
   ],
   "source": [
    "#obtain mean and variance-covariance matrix of returns for k-portfolio 1\n",
    "\n",
    "#Dependencies\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "\n",
    "\n",
    "\n",
    "#input k portfolio 1 dataset comprising 15 stocks\n",
    "StockFileName = 'DJIA_Apr112014_Apr112019_kpf1.csv'\n",
    "Rows = 1259  #excluding header\n",
    "Columns = 15  #excluding date\n",
    "\n",
    "#read stock prices \n",
    "df = pd.read_csv(StockFileName,  nrows= Rows)\n",
    "\n",
    "#extract asset labels\n",
    "assetLabels = df.columns[1:Columns+1].tolist()\n",
    "print('Asset labels of k-portfolio 1: \\n', assetLabels)\n",
    "\n",
    "#read asset prices data\n",
    "StockData = df.iloc[0:, 1:]\n",
    "\n",
    "#compute asset returns\n",
    "arStockPrices = np.asarray(StockData)\n",
    "[Rows, Cols]=arStockPrices.shape\n",
    "arReturns = StockReturnsComputing(arStockPrices, Rows, Cols)\n",
    "\n",
    "#set precision for printing results\n",
    "np.set_printoptions(precision=3, suppress = True)\n",
    "\n",
    "#compute mean returns and variance covariance matrix of returns\n",
    "meanReturns = np.mean(arReturns, axis = 0)\n",
    "covReturns = np.cov(arReturns, rowvar=False)\n",
    "print('\\nMean Returns:\\n', meanReturns)\n",
    "print('\\nVariance-Covariance Matrix of Returns:\\n', covReturns)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The annual average risk free rate of return in USA during April 2019 was 3%. The daily risk free rate is computed  as   \n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![](Lesson6Eqn6_4.png)\n",
    "<h5 align=\"right\">..........(6.4)</h5>\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The following Python code computes the maximal Sharpe Ratio for  $k$-portfolio 1."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Risk free rate (daily %): 0.008\n",
      "Maximal Sharpe Ratio:  [[1.26]] \n",
      "Annualized Risk (%):   [[14.749]] \n",
      "Annualized Expected Portfolio Return(%):   [21.584]\n",
      "\n",
      "Optimal weights (%):\n",
      " [[13.694]\n",
      " [ 0.   ]\n",
      " [17.744]\n",
      " [ 0.   ]\n",
      " [12.151]\n",
      " [ 0.   ]\n",
      " [ 0.   ]\n",
      " [19.058]\n",
      " [ 0.   ]\n",
      " [ 1.151]\n",
      " [ 0.   ]\n",
      " [13.654]\n",
      " [ 0.   ]\n",
      " [22.547]\n",
      " [ 0.   ]]\n"
     ]
    }
   ],
   "source": [
    "#obtain maximal Sharpe Ratio for k-portfolio 1 of Dow stocks\n",
    "\n",
    "#set portfolio size\n",
    "portfolioSize = Columns\n",
    "\n",
    "#set risk free asset rate of return\n",
    "Rf=3  # April 2019 average risk  free rate of return in USA approx 3%\n",
    "annRiskFreeRate = Rf/100\n",
    "\n",
    "#compute daily risk free rate in percentage\n",
    "r0 = (np.power((1 + annRiskFreeRate),  (1.0 / 360.0)) - 1.0) * 100 \n",
    "print('\\nRisk free rate (daily %): ', end=\"\")\n",
    "print (\"{0:.3f}\".format(r0)) \n",
    "\n",
    "#initialization\n",
    "xOptimal =[]\n",
    "minRiskPoint = []\n",
    "expPortfolioReturnPoint =[]\n",
    "maxSharpeRatio = 0\n",
    "\n",
    "#compute maximal Sharpe Ratio and optimal weights\n",
    "result = MaximizeSharpeRatioOptmzn(meanReturns, covReturns, r0, portfolioSize)\n",
    "xOptimal.append(result.x)\n",
    "\n",
    "    \n",
    "#compute risk returns and max Sharpe Ratio of the optimal portfolio   \n",
    "xOptimalArray = np.array(xOptimal)\n",
    "Risk = np.matmul((np.matmul(xOptimalArray,covReturns)), np.transpose(xOptimalArray))\n",
    "expReturn = np.matmul(np.array(meanReturns),xOptimalArray.T)\n",
    "annRisk =   np.sqrt(Risk*251) \n",
    "annRet = 251*np.array(expReturn) \n",
    "maxSharpeRatio = (annRet-Rf)/annRisk \n",
    "\n",
    "#set precision for printing results\n",
    "np.set_printoptions(precision=3, suppress = True)\n",
    "\n",
    "\n",
    "#display results\n",
    "print('Maximal Sharpe Ratio: ', maxSharpeRatio, '\\nAnnualized Risk (%):  ', \\\n",
    "      annRisk, '\\nAnnualized Expected Portfolio Return(%):  ', annRet)\n",
    "print('\\nOptimal weights (%):\\n',  xOptimalArray.T*100 )"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The output shows that the maximal Sharpe Ratio attainable for $k$-portfolio 1 is 1.26 which is good,  going by practical standards. The annual expected portfolio return is 21.584% against an annualized risk of 14.749%. To achieve this, the optimal capital allocations on the assets of $k$-portfolio 1 are as follows:  \n",
    "\n",
    "['AAPL': 13. 694%] , ['BA': 17.744%], ['CSCO': 12.151%],  ['HD': 19.058%], ['JPM': 1.151%],  ['MCD': 13.654%], ['UNH': 22.547%].  \n",
    "  \n",
    "No investments need  be made in the rest of the assets of $k$-portfolio 1 since the optimal weights arrived at for these assets are 0.  \n",
    "However, if the investor desires to invest in all the assets in the $k$-portfolio 1, with the weights distributed across all the assets in the portfolio, all that the investor needs to do is to  redefine the bounds constraint of (6.2) as, $0\\lt W_i\\lt 1$ and run the **scipy**  solver over the optimization model."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Despite the wide use of Sharpe Ratios to compute risk adjusted returns, it is not without its disadvantages. Thus, if the expected returns do not follow a normal distribution or if the portfolios possess non-linear risks, to list a few of the instances, Sharpe Ratios may not deliver  results. Therefore, alternative methodologies such as **Sortino Ratio** and **Treynor Ratio** have emerged as  contenders to Sharpe Ratios. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Companion Reading  "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This blog  is an abridged adaptation of concepts discussed in Chapter 1 and Chapter 3 of [PAI 18] to Dow Jones dataset (DJIA index: April, 2014- April, 2019) and implemented in Python. Readers (read \"worker bees\"),  seeking more information may refer to the corresponding chapters in the  book."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h3 align=\"left\">References</h3>   \n",
    " \n",
    "[SHA 66]  Sharpe, William F. Mutual Fund Performance,  *Journal of Business*, January 1966, pp. 119-138.   \n",
    "\n",
    "[PAI 18]   Vijayalakshmi Pai G. A., Metaheuristics for Portfolio Optimization- An Introduction using MATLAB, Wiley-ISTE, 2018. https://www.mathworks.com/academia/books/metaheuristics-for-portfolio-optimization-pai.html  \n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Next.....Lesson 7: Constrained Portfolio Optimization"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![](Lesson6ExitTailImage.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
